package com.fwtai.builder;

//漂移算法
public class IdWorkerOptimize implements SnowWorker{

  /**
   * 基础时间
  */
  protected final long BaseTime;

  /**
   * 机器码
  */
  protected final short WorkerId;

  /**
   * 机器码位长
  */
  protected final byte WorkerIdBitLength;

  /**
   * 自增序列数位长
  */
  protected final byte SeqBitLength;

  /**
   * 最大序列数（含）
  */
  protected final int MaxSeqNumber;

  /**
   * 最小序列数（含）
  */
  protected final short MinSeqNumber;

  /**
   * 最大漂移次数（含）
  */
  protected final int TopOverCostCount;

  protected final byte _TimestampShift;
  protected final static byte[] _SyncLock = new byte[0];

  protected short _CurrentSeqNumber;
  protected long _LastTimeTick = 0;
  protected long _TurnBackTimeTick = 0;
  protected byte _TurnBackIndex = 0;

  protected boolean _IsOverCost = false;
  protected int _OverCostCountInOneTerm = 0;
  protected int _GenCountInOneTerm = 0;
  protected int _TermIndex = 0;

  public IdWorkerOptimize(final IdWorkerOptions options) {
    BaseTime = options.BaseTime != 0 ? options.BaseTime : 1582136402000L;
    WorkerIdBitLength = options.WorkerIdBitLength == 0 ? 6 : options.WorkerIdBitLength;
    WorkerId = options.WorkerId;
    SeqBitLength = options.SeqBitLength == 0 ? 6 : options.SeqBitLength;
    MaxSeqNumber = options.MaxSeqNumber <= 0 ? (1 << SeqBitLength) - 1 : options.MaxSeqNumber;
    MinSeqNumber = options.MinSeqNumber;
    // TopOverCostCount = options.TopOverCostCount == 0 ? 2000 : options.TopOverCostCount;
    TopOverCostCount = options.TopOverCostCount;
    _TimestampShift = (byte) (WorkerIdBitLength + SeqBitLength);
    _CurrentSeqNumber = MinSeqNumber;
  }

  private void BeginOverCostAction(final long useTimeTick) {}

  private void EndOverCostAction(final long useTimeTick) {
    // if (_TermIndex > 10000) {
    //     _TermIndex = 0;
    // }
  }

  private void BeginTurnBackAction(final long useTimeTick) {}

  private void EndTurnBackAction(final long useTimeTick) {}

  private long NextOverCostId() {
    long currentTimeTick = GetCurrentTimeTick();
    if (currentTimeTick > _LastTimeTick) {
      EndOverCostAction(currentTimeTick);
      _LastTimeTick = currentTimeTick;
      _CurrentSeqNumber = MinSeqNumber;
      _IsOverCost = false;
      _OverCostCountInOneTerm = 0;
      _GenCountInOneTerm = 0;
      return CalcId(_LastTimeTick);
    }
    if (_OverCostCountInOneTerm >= TopOverCostCount) {
      EndOverCostAction(currentTimeTick);
      _LastTimeTick = GetNextTimeTick();
      _CurrentSeqNumber = MinSeqNumber;
      _IsOverCost = false;
      _OverCostCountInOneTerm = 0;
      _GenCountInOneTerm = 0;
      return CalcId(_LastTimeTick);
    }
    if (_CurrentSeqNumber > MaxSeqNumber) {
      _LastTimeTick++;
      _CurrentSeqNumber = MinSeqNumber;
      _IsOverCost = true;
      _OverCostCountInOneTerm++;
      _GenCountInOneTerm++;
      return CalcId(_LastTimeTick);
    }
    _GenCountInOneTerm++;
    return CalcId(_LastTimeTick);
  }

  private long NextNormalId() throws IdWorkerException{
    long currentTimeTick = GetCurrentTimeTick();
    if (currentTimeTick < _LastTimeTick) {
      if (_TurnBackTimeTick < 1) {
        _TurnBackTimeTick = _LastTimeTick - 1;
        _TurnBackIndex++;
        // 每毫秒序列数的前5位是预留位，0用于手工新值，1-4是时间回拨次序
        // 支持4次回拨次序（避免回拨重叠导致ID重复），可无限次回拨（次序循环使用）。
        if (_TurnBackIndex > 4) {
          _TurnBackIndex = 1;
        }
        //BeginTurnBackAction(_TurnBackTimeTick);
      }

      // try {
      // Thread.sleep(1);
      // } catch (InterruptedException e) {
      // e.printStackTrace();
      // }

      return CalcTurnBackId(_TurnBackTimeTick);
    }

    // 时间追平时，_TurnBackTimeTick清零
    if (_TurnBackTimeTick > 0) {
      EndTurnBackAction(_TurnBackTimeTick);
      _TurnBackTimeTick = 0;
    }

    if (currentTimeTick > _LastTimeTick) {
      _LastTimeTick = currentTimeTick;
      _CurrentSeqNumber = MinSeqNumber;
      return CalcId(_LastTimeTick);
    }

    if (_CurrentSeqNumber > MaxSeqNumber) {
      BeginOverCostAction(currentTimeTick);
      _TermIndex++;
      _LastTimeTick++;
      _CurrentSeqNumber = MinSeqNumber;
      _IsOverCost = true;
      _OverCostCountInOneTerm = 1;
      _GenCountInOneTerm = 1;
      return CalcId(_LastTimeTick);
    }
    return CalcId(_LastTimeTick);
  }

  private long CalcId(long useTimeTick) {
    long result = ((useTimeTick << _TimestampShift) +
      ((long) WorkerId << SeqBitLength) +
      (int) _CurrentSeqNumber);

    _CurrentSeqNumber++;
    return result;
  }

  private long CalcTurnBackId(long useTimeTick) {
    long result = ((useTimeTick << _TimestampShift) +
      ((long) WorkerId << SeqBitLength) + _TurnBackIndex);

    _TurnBackTimeTick--;
    return result;
  }

  protected long GetCurrentTimeTick() {
    long millis = System.currentTimeMillis();
    return millis - BaseTime;
  }

  protected long GetNextTimeTick() {
    long tempTimeTicker = GetCurrentTimeTick();

    while (tempTimeTicker <= _LastTimeTick) {
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      tempTimeTicker = GetCurrentTimeTick();
    }

    return tempTimeTicker;
  }

  @Override
  public long nextId() {
    synchronized (_SyncLock) {
      return _IsOverCost ? NextOverCostId() : NextNormalId();
    }
  }
}